package com.pengiummer.blogpublisher.editors;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.registry.EditorRegistry;
import org.eclipse.ui.part.FileEditorInput;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.pengiummer.blogpublisher.popup.actions.BlogClient;
import com.pengiummer.blogpublisher.popup.actions.Post;
import com.pengiummer.blogpublisher.utils.XMLUtils;

public class InteractiveControlPage {
	private class PostManagerHandler extends DefaultHandler {
		private String text;

		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			text = new String(ch, start, length);
		}

		@Override
		public void startDocument() throws SAXException {
			blogTable.removeAll();
		}

		@Override
		public void endElement(String uri, String localName, String name)
				throws SAXException {
			if ("Post".equals(name)) {
				try {
					IFile postFile = project.getFile(new Path(text));

					SAXParser sp = spf.newSAXParser();
					sp.parse(postFile.getContents(), new PostHandler() {
						@Override
						public void endDocument() throws SAXException {
							TableItem item = new TableItem(blogTable, 0);
							item.setText(new String[] { title, id, pubDate, "", text });
							item.setData(text);
						}
					});
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (CoreException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ParserConfigurationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else if ("UserName".equals(name)) {
				userNameTxt.setText(text);
			} else if ("Password".equals(name)) {
				pwdTxt.setText(text);
			} else if ("BlogName".equals(name)) {
				blogNameTxt.setText(text);
			}
		}
	}

	private class PostHandler extends DefaultHandler {
		private String text;
		protected String id;
		protected String title;
		protected String pubDate;
		protected String content;

		private PostHandler() {
			super();
		}

		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			text = new String(ch, start, length);
		}

		@Override
		public void endElement(String uri, String localName, String name)
				throws SAXException {
			if ("Id".equals(name)) {
				id = text;
			} else if ("Title".equals(name)) {
				title = text;
			} else if ("PubDate".equals(name)) {
				pubDate = text;
			} else if ("Content".equals(name)) {
				content = text;
			}
		}

	}

	private final static String DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss";
	private Text blogNameTxt;
	private Text pwdTxt;
	private Text userNameTxt;
	private Table blogTable;
	private final EditorRegistry registry = (EditorRegistry) PlatformUI
			.getWorkbench().getEditorRegistry();
	private IProject project;

	XPath xPath;
	Document mgrDocument;
	MultiPageEditor editor;
	DocumentBuilder docBuilder;
	SAXParserFactory spf;

	public InteractiveControlPage(Composite container, MultiPageEditor editor) {
		this.editor = editor;
		IFile mgrfile = (IFile) editor.getEditorInput().getAdapter(IFile.class);
		project = mgrfile.getProject();
		container.setLayout(new GridLayout(1, false));
		Composite headComposite = new Composite(container, SWT.NONE);
		headComposite.setLayout(new GridLayout(2, false));
		createUserInputs(headComposite);

		createBlogControlBtns(headComposite);

		createBlogList(container);

		try {
			docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			mgrDocument = docBuilder.parse(new ByteArrayInputStream(editor.getEditor().getDocumentProvider()
					.getDocument(editor.getEditorInput()).get().getBytes()));
			spf = SAXParserFactory.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void createUserInputs(Composite headComposite) {
		Composite leftComposite = new Composite(headComposite, SWT.NONE);
		leftComposite.setLayout(new GridLayout(2, false));
		Label userNameLabel = new Label(leftComposite, SWT.NONE);
		userNameLabel.setText("User Name");
		userNameTxt = new Text(leftComposite, SWT.NONE);
		Label pwdLabel = new Label(leftComposite, SWT.NONE);
		pwdLabel.setText("Password");
		pwdTxt = new Text(leftComposite, SWT.NONE);
		pwdTxt.setEchoChar('*');
		Label blogLabel = new Label(leftComposite, SWT.NONE);
		blogLabel.setText("Blog Name");
		blogNameTxt = new Text(leftComposite, SWT.NONE);
	}

	private void createBlogControlBtns(final Composite headComposite) {
		Composite rightComposite = new Composite(headComposite, SWT.NONE);
		rightComposite.setLayout(new GridLayout(1, false));
		Button importBtn = new Button(rightComposite, SWT.PUSH);
		importBtn.setText("Import Posts");
		importBtn.addListener(SWT.Selection, new Listener() {
			@Override
			public void handleEvent(Event event) {
				BlogClient client = new BlogClient(blogNameTxt.getText());

				try {
					client.authenticate(userNameTxt.getText(), pwdTxt.getText());
					client.initConnection();
					List<Post> posts = client.getAllPosts();
					XMLUtils.removeChildNodes(XMLUtils.getNodeByPath(mgrDocument
							.getDocumentElement(), "Security", true));
					Node userNameNode = XMLUtils.getNodeByPath(mgrDocument
							.getDocumentElement(), "Security/UserName", true);
					userNameNode.appendChild(mgrDocument.createTextNode(userNameTxt
							.getText()));
					Node passwordNode = XMLUtils.getNodeByPath(mgrDocument
							.getDocumentElement(), "Security/Password", true);
					passwordNode.appendChild(mgrDocument.createTextNode(pwdTxt.getText()));
					Node blogNameNode = XMLUtils.getNodeByPath(mgrDocument
							.getDocumentElement(), "Security/BlogName", true);
					blogNameNode.appendChild(mgrDocument.createTextNode(blogNameTxt
							.getText()));

					Node postsNode = XMLUtils.getNodeByPath(
							mgrDocument.getDocumentElement(), "Posts", true);
					XMLUtils.removeChildNodes(postsNode);
					for (Post post : posts) {
						Node postNode = mgrDocument.createElement("Post");
						postsNode.appendChild(postNode);

						String postId = post.getId();
						String fileName = postId + ".xml";
						postNode.appendChild(mgrDocument.createTextNode(fileName));

						savePostDocument(post, fileName);
					}
					String docContent = XMLUtils.saveDocumentToString(mgrDocument);
					editor.getEditor().getDocumentProvider().getDocument(
							editor.getEditorInput()).set(docContent);
					refresh();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		});
		Button newBtn = new Button(rightComposite, SWT.NONE);
		newBtn.setText("Create Post");
		newBtn.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				long currenttime = System.currentTimeMillis();
				String fileName = String.valueOf(currenttime).concat(".xml");
				Post post = new Post("", "Change to your title", "Change to your post content", null);
				try {
					savePostDocument(post, fileName);
					Node postsNode = XMLUtils.getNodeByPath(
							mgrDocument.getDocumentElement(), "Posts", true);
					Node postNode = mgrDocument.createElement("Post");
					postNode.appendChild(mgrDocument.createTextNode(fileName));
					postsNode.appendChild(postNode);
					String docContent = XMLUtils.saveDocumentToString(mgrDocument);
					editor.getEditor().getDocumentProvider().getDocument(
							editor.getEditorInput()).set(docContent);
					refresh();
				} catch (TransformerException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (CoreException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SAXException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (XPathExpressionException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ParserConfigurationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}

	private void savePostDocument(Post post, String fileName)
			throws TransformerException, CoreException, XPathExpressionException, SAXException, IOException, ParserConfigurationException {
		IFile postFile = project.getFile(new Path(fileName));
		Document postDocument = docBuilder.newDocument();
		Element postDocumentRoot = postDocument.createElement("Post");
		postDocument.appendChild(postDocumentRoot);

		Node idNode = XMLUtils.getNodeByPath(postDocumentRoot, "Id", true);
		idNode.appendChild(postDocument.createTextNode(post.getId()));

		Node titleNode = XMLUtils.getNodeByPath(postDocumentRoot, "Title", true);
		titleNode.appendChild(postDocument.createTextNode(post.getTitle()));

		Node pubDateNode = XMLUtils
		.getNodeByPath(postDocumentRoot, "PubDate", true);
		if(post.getPublishDate() != null){
			String pubDate = new SimpleDateFormat(DATE_FORMAT).format(post
					.getPublishDate());
			pubDateNode.appendChild(postDocument.createTextNode(pubDate));
		}

		Node contentNode = XMLUtils
				.getNodeByPath(postDocumentRoot, "Content", true);
		contentNode.appendChild(postDocument.createCDATASection(post
				.getHtmlContent()));

		Node pi = postDocument.createProcessingInstruction("xml-stylesheet",
				"type=\"text/xsl\" href=\"renderpost.xsl\"");
		postDocument.insertBefore(pi, postDocumentRoot);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		XMLUtils.saveDocument(postDocument, baos);
		InputStream is = new ByteArrayInputStream(baos.toByteArray());
		if (postFile.exists()) {
			postFile.setContents(is, true, true, new NullProgressMonitor());
		} else {
			postFile.create(is, true, new NullProgressMonitor());
		}
		refresh();
	}

	private void createBlogList(Composite topComposite) {
		Composite botComposite = new Composite(topComposite, SWT.NONE);
		botComposite.setLayout(new GridLayout(1, false));
		blogTable = new Table(botComposite, SWT.MULTI | SWT.FULL_SELECTION);
		Menu menu = new Menu(topComposite.getShell());
		MenuItem publishMenuItem = new MenuItem(menu, SWT.DROP_DOWN);
		publishMenuItem.setText("Publish");
		publishMenuItem.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				try {
					final String fileName = (String) blogTable.getSelection()[0].getData();
					IFile postFile = project.getFile(new Path(fileName));
					SAXParser sp = spf.newSAXParser();

					sp.parse(postFile.getContents(), new PostHandler() {
						@Override
						public void endDocument() throws SAXException {
							BlogClient client = new BlogClient(blogNameTxt.getText());

							try {
								client.authenticate(userNameTxt.getText(), pwdTxt.getText());
								client.initConnection();
								Post post = client.publishPost(id, title, content, userNameTxt
										.getText(), userNameTxt.getText());
								savePostDocument(post, fileName);
							} catch (Exception e1) {
								e1.printStackTrace();
							}
						}
					});
				} catch (Exception e2) {
					e2.printStackTrace();
				}
			}
		});
		blogTable.setMenu(menu);
		blogTable.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseDoubleClick(MouseEvent e) {
				IFile file = project.getFile(new Path(blogTable.getSelection()[0]
						.getText(4)));
				IEditorDescriptor preferredEditor = registry
						.getDefaultEditor((String) blogTable.getSelection()[0].getData());
				try {
					editor.getSite().getPage().openEditor(new FileEditorInput(file),
							preferredEditor.getId());
				} catch (PartInitException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});
		TableColumn col1 = new TableColumn(blogTable, SWT.LEFT);
		col1.setText("Title");
		col1.setWidth(200);
		TableColumn col2 = new TableColumn(blogTable, SWT.LEFT);
		col2.setText("Id");
		col2.setWidth(80);
		TableColumn col3 = new TableColumn(blogTable, SWT.LEFT);
		col3.setText("Publish Date");
		col3.setWidth(80);
		TableColumn col4 = new TableColumn(blogTable, SWT.LEFT);
		col4.setText("Modify Date");
		col4.setWidth(80);
		TableColumn col5 = new TableColumn(blogTable, SWT.LEFT);
		col5.setText("File Name");
		col5.setWidth(80);
		blogTable.setItemCount(25);

		blogTable.setHeaderVisible(true);
		blogTable.setLinesVisible(true);
	}

	public void refresh() throws XPathExpressionException, SAXException,
			IOException, ParserConfigurationException {
		SAXParser sp = spf.newSAXParser();
		sp.parse(new ByteArrayInputStream(editor.getEditor().getDocumentProvider()
				.getDocument(editor.getEditorInput()).get().getBytes()),
				new PostManagerHandler());
	}
}
